// app/extend/helper.js
const basics = require('../common/basics');
const CryptoJS = require('crypto-js');
const jwt = require('jsonwebtoken');
const TOTP = require('totp.js');


// 封装的工具函数
module.exports = {
  // 判断有没有小数点
  isDot(str) {
    str = str.toString();
    return /[\.]/.test(str);
  },

  // 两头去空格
  // 参数: 字符串, 数字
  // 返回值: 字符串
  clearBlank(str) {
    str = str.toString();
    if (str === '') {
      return str;
    }
    return str.replace(/(^\s*)|(\s*$)/g, '');
  },

  // 16进制转换10进制
  // 参数: 字符串, 数字
  // 返回值: 字符串
  hexToDec(str) {
    return BigInt(str)
      .toString();
  },

  // 科学计数法转为string
  scientificNotationToString(param) {
    let strParam = String(param);
    let flag = /e/.test(strParam);
    if (!flag) return param;

    // 指数符号 true: 正，false: 负
    let sysbol = true;
    if (/e-/.test(strParam)) {
      sysbol = false;
    }
    // 指数
    let index = Number(strParam.match(/\d+$/)[0]);
    // 基数
    let basis = strParam.match(/^[\d\.]+/)[0].replace(/\./, '');

    if (sysbol) {
      return basis.padEnd(index + 1, 0);
    } else {
      return basis.padStart(index + basis.length, 0)
        .replace(/^0/, '0.');
    }
  },

  // 加减乘除
  // 参数: 数字,字符串,16进制都可以(需要加0x前缀), 科学计数法(有bug,不建议使用); 建议统一使用十进制字符串进行计算;
  add(a, b) {
    return basics.basAdd(a, b);
  },
  sub(a, b) {
    return basics.basSub(a, b);
  },
  mul(a, b) {
    return basics.basMul(a, b);
  },
  div(a, b) {
    return basics.basDiv(a, b);
  },
  pow(a, b) {
    return basics.basPow(a, b);
  },
  // 比较大小; gte=是否大于等于, gt=是否大于, eq=是否相等, lt=是否小于, lte=是否小于等于
  // 参数: 统一使用十进制的字符串,
  // 返回值: 布尔类型
  gte(a, b) {
    return basics.basGte(a, b);
  },
  gt(a, b) {
    return basics.basGt(a, b);
  },
  eq(a, b) {
    return basics.basEq(a, b);
  },
  lt(a, b) {
    return basics.basLt(a, b);
  },
  lte(a, b) {
    return basics.basLte(a, b);
  },

  // 保留小数点后N位; 向下取整
  // 参数1: 数字字符串, 不能是科学计数法
  // 参数2: 数字; 保留小数的位数, 不写默认保存全部小数位
  // 返回值: 字符串
  toFixedN(str, N) {
    if (str === '0' || str === '') {
      return '0';
    } else if (this.isDot(str)) {
      let arr = str.split('.');
      if (arr[1].length >= N + 1) {
        return arr[0] + '.' + arr[1].slice(0, N);
      } else {
        return arr[0] + '.' + arr[1].slice(0, arr[1].length);
      }
    } else {
      return str;
    }
  },

  // 补0
  // 参数1: 十进制字符串, 16进制, 数字类型, 不能是科学计数法;
  // 参数2: 不写默认补6个0, 写18则为18个0
  // 返回值: 字符串
  mulZero(str, N = '6') {
    str = str.toString();
    if (str === '0' || str === '') {
      return '0';
    }
    let zero;
    if (N === '18') {
      zero = '1000000000000000000';
    } else {
      zero = '1000000';
    }
    return this.mul(str, zero);
  },

  // 去0
  // 参数1: 十进制字符串, 16进制, 数字类型, 不能是科学计数法;
  // 参数2: 不写默认补6个0, 写18则为18个0
  // 返回值: 字符串
  divZero(str, N = '6') {
    str = str.toString();
    if (str === '0' || str === '') {
      return '0';
    }
    let zero;
    if (N === '18') {
      zero = '1000000000000000000';
    } else {
      zero = '1000000';
    }
    return this.div(str, zero);
  },

  // 16进制或10进制-->除N个0-->保留小数点N位
  // 参数1: 字符串, 可以是10进制的, 也可以是16进制的
  // 参数2: 去N个0, '6'=6个0, '18'=18个0;
  // 参数3: 保留的位数, 数字, 传入字符串几就是保留几位小数位, 向下取整的, 不写默认值保留全部小数
  hexToDecDiv6N(str, N1 = '6', N2) {
    str = str.toString();
    if (str === '0') {
      return '0';
    }
    if (str.indexOf('x') >= 0) {
      // 是16进制, 转换成10进制
      str = this.hexToDec(str);
    }
    str = this.divZero(str, N1);
    str = this.toFixedN(str, N2);
    return str;
  },

  // 加密
  encryptByDESModeCBC(message) {
    const {app} = this;
    const key = app.Init.key;
    const keyHex = CryptoJS.enc.Utf8.parse(key);
    const ivHex = CryptoJS.enc.Utf8.parse(key);
    const encrypted = CryptoJS.DES.encrypt(message, keyHex, {
        iv: ivHex,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
      }
    );
    return encrypted.ciphertext.toString(CryptoJS.enc.Base64);
  },

  // 解密
  decryptByDESModeCBC(ciphertext) {
    const {app} = this;
    const key = app.Init.key;
    const keyHex = CryptoJS.enc.Utf8.parse(key);
    const ivHex = CryptoJS.enc.Utf8.parse(key);
    const decrypted = CryptoJS.DES.decrypt({
      ciphertext: CryptoJS.enc.Base64.parse(ciphertext)
    }, keyHex, {
      iv: ivHex,
      mode: CryptoJS.mode.CBC,
      padding: CryptoJS.pad.Pkcs7
    });
    return decrypted.toString(CryptoJS.enc.Utf8);
  },

  // 签名token
  async signToken(user) {
    const {app} = this;
    const key = app.Init.key;
    const time = app.Init.jwtTime;
    return jwt.sign({
      user: user,
      // 单位是秒值,
      exp: Math.floor(Date.now() / 1000) + time
    }, key);
  },

  // 解密签名
  async verifyToken(token) {
    const {app} = this;
    const key = app.Init.key;
    return jwt.verify(token, key);
  },

  // 比较两个数组有不一样的地方, 把不一样的地方放进一个新的数组里面
  // 参数1: 多的那个数组
  // 参数2: 少的那个数组
  // 返回值: 不一样的数据数组
  twoArrayRes(arr1, arr2) {
    const res = [];
    for (let i = 0; i < arr1.length; i++) {
      if(!arr2.includes(arr1[i])) {
        res.push(arr1[i])
      }
    }
    return res;
  },

  // 生成一个新的code
  newCode() {
    return TOTP.randomKey();
    // console.log('随机的Key', key);
  },

  // 验证code
  verifyCode(key, code) {
    const totp = new TOTP(key);
    return totp.verify(code);
  },

  // 地址转换, T类型转换成0x类型
  async addressChange(addressT) {
    const {app, ctx, service} = this;
    addressT = await service.eth.addressToHex(addressT);
    if(addressT.indexOf('41') === 0) {
      return addressT.replace('41', '0x');
    }
    return addressT
  },

  // 生成随机数; 使用的是时间错
  createNonce() {
    let nonce = Date.now();
    return nonce + '';
  },


};
